package com.hrt.datasender.datadao.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.btcode.common.MyLog;
import com.btcode.db.executer.IDataExecuter;
import com.btcode.db.result.Row;
import com.btcode.db.sqlparameter.SQLParameterList;
import com.btcode.log.ILog;
import com.btcode.orm.executer.IORMExecuter;
import com.hrt.datasender.datadao.model.BcMonitorParamDictModel;
import com.hrt.datasender.datadao.model.BdSourceModel;
import com.hrt.datasender.web.WebMain;
import com.hrt.datasender.web.bcmonitorparamdict.BcMonitorParamDictService;
import com.hrt.db.DBManager;

public final class BdSourceService {
    private static ILog log;
    private static volatile BdSourceService instance;
    private final int dataRetentTime = 7;

    private BdSourceService() {
        if (log == null) {
            log = MyLog.getInstance().getLogger(getClass());
        }
    }

    public static BdSourceService getInstance() {
        if (instance == null) {
            synchronized (BdSourceService.class) {
                if (instance == null) {
                    instance = new BdSourceService();
                }
            }
        }
        return instance;
    }

    public void add(List<BdSourceModel> models) {
        IORMExecuter executer = DBManager.getORMExecuter();
        executer.creates(models);
    }

    // 获取时间段内最后一条数据
    public static Double getLastData(String param, Calendar startTime, Calendar endTime) {
        Double result = null;
        try {
            String sql = " SELECT MEAS_RE FROM BD_SOURCE WHERE DATATIME >=@START AND DATATIME <@END" +
                " and param_code_bus = @PARAM" +
                " order by DATATIME desc limit 0,1";
            SQLParameterList pc = new SQLParameterList();
            pc.put("PARAM", param);
            if("mysql".equals(WebMain.DBTYPE)){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pc.put("START",sdf.format(startTime.getTime()));
                pc.put("END", sdf.format(endTime.getTime()));
            }
            else{
                pc.put("START", startTime.getTimeInMillis());
                pc.put("END", endTime.getTimeInMillis());
            }

            List<Row> rows = DBManager.getDataExecuter().queryList(sql, pc);
            if (rows != null && rows.size() > 0) {
                Row row = rows.get(0);
                result = Double.valueOf(row.getSafeString("MEAS_RE"));
            }
        }
        catch (Exception e) {
            log.error("获取时间段内最后一条数据错误",e);
        }
        return result;
    }

    /**
     * 获取区间流量,表头流量不可能为0，为0的数据不纳入统计
     * 如果实际出现表头流量为0的情况，
     * @param param
     * @param startTime
     * @param endTime
     * @return
     */
    public static Double getIntervalFlow(String param, Calendar startTime, Calendar endTime) {

        Double intervalFlow = null;
        try {
            String sql = "select meas_re from BD_SOURCE" +
                    " where datatime >=@START and datatime <@END" +
                    " and param_code_bus =@PARAM" +
                    " and MEAS_RE >= 0";
            SQLParameterList pc = new SQLParameterList();
            pc.put("PARAM", param);
            if("mysql".equals(WebMain.DBTYPE)){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pc.put("START",sdf.format(startTime.getTime()));
                pc.put("END", sdf.format(endTime.getTime()));
            }
            else{
                pc.put("START", startTime.getTimeInMillis());
                pc.put("END", endTime.getTimeInMillis());
            }
            List<Row> datRows = DBManager.getDataExecuter().queryList(sql, pc);
            if(datRows.size()==0){
                return null;
            }

            sql = "select max(meas_re) - min(meas_re) as intervalMeas from BD_SOURCE " +
                    " where datatime >=@START and datatime <@END" +
                    " and param_code_bus =@PARAM" +
                    " and MEAS_RE >= 0";

            List<Row> rows = DBManager.getDataExecuter().queryList(sql, pc);
            if (rows != null && rows.size() > 0) {
                Row row = rows.get(0);
                String value = row.getSafeString("INTERVALMEAS");
                log.info(value);
                if(value!=null&&!"".equals(value)){
                    intervalFlow = Double.valueOf(row.getSafeString("INTERVALMEAS"));
                }else{
                    intervalFlow = 0.0;
                }
            }
        }
        catch (Exception e) {
            log.error("获取区间流量错误",e);
        }
        return intervalFlow;
    }

    // 获取算术均值
    public static Double getArithmeticAvg(String param, Calendar startTime, Calendar endTime,String dataSource) {
        Double avg = null;
        try {
            String sql = "select avg(meas_re) as avg from " + dataSource +
                    " where datatime >=@START and datatime <@END" +
                    " and param_code_bus =@PARAM";
            SQLParameterList pc = new SQLParameterList();
            pc.put("PARAM", param);
            if("mysql".equals(WebMain.DBTYPE)){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pc.put("START",sdf.format(startTime.getTime()));
                pc.put("END", sdf.format(endTime.getTime()));
            }
            else{
                pc.put("START", startTime.getTimeInMillis());
                pc.put("END", endTime.getTimeInMillis());
            }
            List<Row> rows = DBManager.getDataExecuter().queryList(sql, pc);
            if (rows != null && rows.size() > 0) {
                Row row = rows.get(0);
                if("".equals(row.getSafeString("AVG"))){
                    return null;
                }
                else{
                    avg = Double.valueOf(row.getSafeString("AVG"));
                }

            }
        } 
        catch (Exception e) {
            log.error("获取算术均值错误",e);
        }
        return avg;
    }

    /**
     * 获取pH均值,pH不可能为0，为0的数据不纳入统计
     * @param param
     * @param startTime
     * @param endTime
     * @return
     */
    public static Double getPHAvg(String param, Calendar startTime, Calendar endTime,String dataSource) {
        Double pHAvg = null;
        try {
            // 先判断混合后是酸性还是碱性
            // 取出所有数据
            String sql = "select * from " + dataSource +
                    " where datatime >=@START  and datatime <@END " +
                    " and param_code_bus =@PARAM " +
                    " and MEAS_RE > 0";
            SQLParameterList pc = new SQLParameterList();
            pc.put("PARAM", param);
            if("mysql".equals(WebMain.DBTYPE)){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pc.put("START",sdf.format(startTime.getTime()));
                pc.put("END", sdf.format(endTime.getTime()));
            }
            else{
                pc.put("START", startTime.getTimeInMillis());
                pc.put("END", endTime.getTimeInMillis());
            }
            List<Row> rows = DBManager.getDataExecuter().queryList(sql, pc);
            // 氢离子
            Double hydrion = 0.0;
            // 氢氧根离子
            Double hydrionIon = 0.0;
            //pH计算底数
            final int phBaseNumber = 10;   
            //pH最大值
            final int phMaxValue = 14;  
            //pH中间值
            final int phInterValue = 7;  

            if (rows != null && rows.size() > 0) {
                for (Row row : rows) {
                    // 取出每个pH值
                    Double pH = Double.valueOf(row.getSafeString("MEAS_RE"));
                    hydrion += Math.pow(phBaseNumber, -pH);
                    hydrionIon += Math.pow(phBaseNumber, -(phMaxValue - pH));
                }
                // 判断混合后是酸性还是碱性
                if (hydrion >= Math.pow(phBaseNumber, -phInterValue)) {
                    // 酸性
                    pHAvg = -log10(hydrion / rows.size(), phBaseNumber);
                }
                else {
                    // 碱性
                    pHAvg = -log10(hydrionIon / rows.size(), phBaseNumber);
                }
            }
        } 
        catch (Exception e) {
            log.error("获取pH均值错误",e);
        }
        return pHAvg;
    }

    // 求底数为10的对数值
    public static double log10(double value, double base) {
        return Math.log(value) / Math.log(base);
    }

    // BD_SOURCE数据保留7天
    public void clearRecord() {
        IDataExecuter dataExecuter = DBManager.getDataExecuter();
        String sql = " DELETE FROM BD_SOURCE WHERE DATATIME < @date  ";
        SQLParameterList pc = new SQLParameterList();
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, -dataRetentTime);
        Date date = cal.getTime();
        pc.put("date", date);
        dataExecuter.delete(sql, pc);
    }

    /**
     * 计算加权均值,取出流量数据，无流量数据：计算算术均值
     * 加权均值：sum(监测值*流量)/sum(流量)
     * @param param
     * @param startTime
     * @param endTime
     * @return
     */
    public static Double getWeightAvg(String param, Calendar startTime, Calendar endTime,String dataSource) {
        Double avg = null;
        try {
            String sql = "select datatime,meas_re from " + dataSource +
                    " where datatime >=@START and datatime <@END" +
                    " and param_code_bus =@PARAM";
            SQLParameterList pc = new SQLParameterList();
            pc.put("PARAM", "B01TOTAL");
            if("mysql".equals(WebMain.DBTYPE)){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pc.put("START",sdf.format(startTime.getTime()));
                pc.put("END", sdf.format(endTime.getTime()));
            }
            else{
                pc.put("START", startTime.getTimeInMillis());
                pc.put("END", endTime.getTimeInMillis());
            }
            List<Row> rows = DBManager.getDataExecuter().queryList(sql, pc);
            if (rows != null && rows.size() > 0) {
                sql = "select datatime,meas_re from " + dataSource +
                        " where datatime >=@START and datatime <@END" +
                        " and param_code_bus =@PARAM";
                pc.clear();
                if("mysql".equals(WebMain.DBTYPE)){
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    pc.put("START",sdf.format(startTime.getTime()));
                    pc.put("END", sdf.format(endTime.getTime()));
                }
                else{
                    pc.put("START", startTime.getTimeInMillis());
                    pc.put("END", endTime.getTimeInMillis());
                }
                pc.put("PARAM", param);
                List<Row> paramRows = DBManager.getDataExecuter().queryList(sql, pc);

                Double emisions = 0.0;
                Double totalFlow = 0.0;
                for (Row paramRow : paramRows) {
                    //根据datatime获取对应的流量
                    Double value = paramRow.getSafeDouble("meas_re");
                    String datatime = paramRow.getSafeDouble("datatime")+"";
                    Row flowRow = getDataByKey(rows,"datatime",datatime);
                    if(flowRow!=null){
                        Double flow = flowRow.getSafeDouble("meas_re");
                        emisions += flow * value;
                        totalFlow += flow;
                    }
                }
                /**
                 * 流量为0的情况，下计算算术均值
                 */
                if(totalFlow==0.0){
                    return getArithmeticAvg(param,startTime,endTime,dataSource);
                }
                avg = emisions/totalFlow;
            }
            else{
                /**
                 * 无流量的数据的话，计算算术均值
                 */
                return getArithmeticAvg(param,startTime,endTime,dataSource);
            }
        }
        catch (Exception e) {
            log.error("获取加权均值错误",e);
        }
        return avg;
    }

    public static Row getDataByKey(List<Row> rows,String key,String value){
        try{
            if(rows.size()>0) {
                for(int i=0;i<rows.size();i++){
                    Row row = rows.get(i);
                    if(value.equals(row.getSafeDouble(key)+"")) {
                        return row;
                    }
                }
            }
        }
        catch (Exception e) {
            log.error("getDataByKey出错",e);
        }
        return null;
    }

    // 单位转换
    public static List<BdSourceModel> unitConver(List<BdSourceModel> models) {
        try {
            for (int i = 0; i < models.size(); i++) {
                String param = models.get(i).getParamCodeBus();
                BcMonitorParamDictModel paramModel = new BcMonitorParamDictModel();
                paramModel.setParamCodeBus(param);
                paramModel = BcMonitorParamDictService.getInstance().getModel(paramModel);
                String multiple = paramModel.getMultiple();
                String molWeight = paramModel.getMolWeight();

                if (paramModel.getUnitConver() != null) {
                    switch (paramModel.getUnitConver()) {
                        case "0": // 乘倍数
                            if (multiple != null && !"".equals(multiple)) {
                                Double dMultiple = Double.parseDouble(multiple);
                                models.get(i).setMeasRe(models.get(i).getMeasRe() * dMultiple);
                            }
                            break;
                        case "1": // 除倍数
                            if (multiple != null && !"".equals(multiple)) {
                                Double dMultiple = Double.parseDouble(multiple);
                                models.get(i).setMeasRe(models.get(i).getMeasRe() / dMultiple);
                            }
                            break;
                        case "2": // 乘分子量除22.4
                            if (molWeight != null && !"".equals(molWeight)) {
                                Double dMolWeight = Double.parseDouble(molWeight);
                                models.get(i).setMeasRe(models.get(i).getMeasRe() * dMolWeight / 22.4);
                            }
                            break;
                        case "3": // 乘分子量除22.4乘倍数
                            if (multiple != null && molWeight != null && !"".equals(molWeight) && !"".equals(multiple)) {
                                Double dMultiple = Double.parseDouble(multiple);
                                Double dMolWeight = Double.parseDouble(molWeight);
                                models.get(i).setMeasRe(models.get(i).getMeasRe() * dMolWeight / 22.4 * dMultiple);
                            }
                            break;
                        case "4": // 乘分子量除22.4除倍数
                            if (multiple != null && molWeight != null && !"".equals(molWeight) && !"".equals(multiple)) {
                                Double dMultiple = Double.parseDouble(multiple);
                                Double dMolWeight = Double.parseDouble(molWeight);
                                models.get(i).setMeasRe(models.get(i).getMeasRe() * dMolWeight / 22.4 / dMultiple);
                            }
                            break;
                        default: // 默认不处理
                            break;
                    }
                }

            }
        }
        catch (Exception e) {
            log.error("单位转换失败", e);
        }
        return models;
    }

    /**
     * 量程转换
     * @param models
     * @return
     */
    public static List<BdSourceModel> rangeConver(List<BdSourceModel> models) {
        try {
            for(BdSourceModel model:models){
                Double measRe = model.getMeasRe();
                String param = model.getParamCodeBus();
                BcMonitorParamDictModel paramModel = new BcMonitorParamDictModel();
                paramModel.setParamCodeBus(param);
                paramModel = BcMonitorParamDictService.getInstance().getModel(paramModel);
                String isRangeConversion = paramModel.getIsRangeConversion();
                if (isRangeConversion!=null&&"0".equals(isRangeConversion)) {
                    Double rangeDown = Double.valueOf(paramModel.getRangeDown());
                    Double rangeUp = Double.valueOf(paramModel.getRangeUp());
                    Double digitalRangeDown = Double.valueOf(paramModel.getDigitalRangeDown());
                    Double digitalRangeUp = Double.valueOf(paramModel.getDigitalRangeUp());
                    /**
                     * 公式:测量值=(参数量程上限-参数量程下限)/(数字量程上限-数字量程下限)*（数字量-数字量程下限）
                     */
                    Double value = (rangeUp-rangeDown)/(digitalRangeUp-digitalRangeDown)*(measRe-digitalRangeDown);
                    model.setMeasRe(value);
                }
            }
        }
        catch (Exception e) {
            log.error("量程转换失败", e);
        }
        return models;
    }

}